using System;
using System.Configuration;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using Guadagno.Utilities.Configuration;


namespace ApplicationPlugins
{
    /// <summary>
    /// The configuration class for Run Command plugin
    /// </summary>
    public class RunCommandConfig : ConfigurationBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="RunCommandConfig"/> class.
        /// </summary>
        public RunCommandConfig() { }
        /// <summary>
        /// Initializes a new instance of the <see cref="RunCommandConfig"/> class.
        /// </summary>
        /// <param name="stage">The stage.</param>
        public RunCommandConfig(string stage) : base(stage) { }
        /// <summary>
        /// Initializes a new instance of the <see cref="RunCommandConfig"/> class.
        /// </summary>
        /// <param name="stage">The stage.</param>
        /// <param name="filename">The filename.</param>
        public RunCommandConfig(string stage, string filename) : base(stage, filename) { }

        #region Public Properties From XML

        /// <summary>
        /// Gets the schedule configuration section.
        /// </summary>
        /// <value>The schedule.</value>
        public string Schedule { get { return this["Schedule"]; } }
        /// <summary>
        /// Gets the log4net configuration section.
        /// </summary>
        /// <value>The log4 net config.</value>
        public string Log4NetConfig { get { return this["log4net"]; } }
        /// <summary>
        /// Gets the command section of the configuration file.
        /// </summary>
        /// <value>The commands.</value>
        public string Commands { get { return this["Commands"]; } }

        #endregion Public Properties From XML

        #region Public Properties Derived
        /// <summary>
        /// Returns a List &lt;<see cref="ProcessStartInfo"/> &gt;
        /// </summary>
        public List<ProcessStartInfo> CommandsToRun
        {
            get
            {
                return loadProcessStartInfos(this["Commands"]);
            }
        }
        #endregion Public Properties Derived

        #region Private Methods

        #region loadProcessStartInfos
        /// <summary>
        /// Reads the Commands XML an converts into a list of <see cref="ProcessStartInfo"/>
        /// objects
        /// </summary>
        /// <param name="configSection">The Commands section of the XML file.</param>
        /// <returns>A List &lt;<see cref="ProcessStartInfo"/> &gt; objects</returns>
        private List<ProcessStartInfo> loadProcessStartInfos(string configSection)
        {
            #region Variables

            List<ProcessStartInfo> psis = new List<ProcessStartInfo>();

            #endregion Variables

            #region Data Validation

            if (string.IsNullOrEmpty(configSection)) return psis;

            #endregion Data Validation

            try
            {
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(configSection);

                XmlNode commands = xml.SelectSingleNode("Commands");
                foreach (XmlNode command in commands.ChildNodes)
                {
                    // Each of the child nodes should be a "Command"
                    if (command.Name != "Command") continue;

                    ProcessStartInfo psi = new ProcessStartInfo();
                    foreach (XmlNode childNode in command.ChildNodes)
                    {
                        if (childNode.NodeType == XmlNodeType.Comment) continue;

                        switch (childNode.Name)
                        {
                            case "Arguments":
                                psi.Arguments = childNode.InnerText;
                                break;
                            case "CreateNoWindow":
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.CreateNoWindow = getBool(childNode.InnerText);
                                break;
                            case "Domain":
                                psi.Domain = childNode.InnerText;
                                break;
                            case "ErrorDialog":
                                psi.ErrorDialog = false;
                                break;
                            case "FileName":
                                psi.FileName = childNode.InnerText;
                                break;
                            case "LoadUserProfile":
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.LoadUserProfile = getBool(childNode.InnerText);
                                break;
                            case "Password":
                                // .Password is of type System.Security.SecureString
                                System.Security.SecureString password = new System.Security.SecureString();
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                {
                                    char[] chars = childNode.InnerText.ToCharArray();
                                    foreach (char x in chars)
                                    {
                                        password.AppendChar(x);
                                    }
                                    psi.Password = password;
                                }
                                break;
                            case "RedirectStandardError":
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.RedirectStandardError = getBool(childNode.InnerText);
                                break;
                            case "RedirectStandardInput":
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.RedirectStandardInput = getBool(childNode.InnerText);
                                break;
                            case "RedirectStandardOutput":
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.RedirectStandardOutput = getBool(childNode.InnerText);
                                break;
                            case "StandardErrorEncoding":
                                //System.Text.Encoding
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.StandardErrorEncoding = System.Text.Encoding.GetEncoding(childNode.InnerText);
                                break;
                            case "StandardOutputEncoding":
                                //System.Text.Encoding
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.StandardOutputEncoding = System.Text.Encoding.GetEncoding(childNode.InnerText);
                                break;
                            case "UserName":
                                psi.UserName = childNode.InnerText;
                                break;
                            case "UseShellExecute":
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.UseShellExecute = getBool(childNode.InnerText);
                                break;
                            case "Verb":
                                psi.Verb = childNode.InnerText;
                                break;
                            case "WindowStyle":
                                if (!string.IsNullOrEmpty(childNode.InnerText))
                                    psi.WindowStyle = (ProcessWindowStyle)Enum.Parse(typeof(ProcessWindowStyle), childNode.InnerText);
                                break;
                            case "WorkingDirectory":
                                psi.WorkingDirectory = childNode.InnerText;
                                break;
                        }
                    }
                    // Add the PSI to the List of PSIs
                    psis.Add(psi);
                }

            }
            catch (Exception ex)
            {
                throw new ConfigurationErrorsException("There was an exception raised while loading the Commands configuration.", ex);
            }

            return psis;

        }
        
        #endregion loadProcessStartInfos

        #endregion Private Methods

    }
}
